
var Suggest = new Class({
    Implements: [Options, Events],
    options: {
        url: null,
        table: 'sugcust',
        tagid: null,
        minLength: 3
    },
    cachedData: new Hash(),
    suggestionData: null,
    currentSelection: null,
    ulTag: null,
    inputTag: null,
    enteredText: '',
    suggestionsShown: false,
    initialize: function(options) {
        this.setOptions(options);
        this.tag = document.id(this.options.tagid);
        if(!this.tag) return;

        document.body.addEvent('click', function() {
            this.gcList();
        }.bind(this));

        this.setInput();

        this.build();
    },
    setInput: function() {

        var srchead = this.tag.getElements('th[id="srchead"]');
        var tagth,text;
        for(var i = 0; i < srchead.length; i++) {
            tagth = srchead[i];
            text = tagth.get('text');

            tagth.setStyle('line-height','18px').empty().adopt(
                new Element('input#input_0[type=text][maxlength=50][style=display:none;]',{
                    'events':{
                        'dblclick': this.handleInput.bind(this),
                        'keydown': this.keyDownEvent.bind(this),
                        'keyup': this.keyUpEvent.bind(this)
                    }
                }).store('col', tagth.retrieve('tbname')),
                new Element('em[text=' + text + ']'),
                new Element('a[href=javascript:;][html=&nbsp;]', {
                    'events': {
                        'click': this.changeInput.bind(this),
                        'focus': function() {this.blur();}
                    }
                })
            );
        }

        this.inputTag = document.id('input_0');

    },
    keyDownEvent: function(ev) {

        var next = null;
        if(ev.key == 'enter') {
            ev.stop();
            this.onChoice(this.currentSelection);
        }
        else if(ev.key == 'tab') {
            this.onChoice(this.currentSelection);
        }
        else if(ev.key == 'down' || ev.key == 'up') {
            ev.stop();
            if(ev.key == 'down') {
                if(this.currentSelection == null || this.currentSelection.getNext('li') == null) {
                    next = this.ulTag.getFirst('li');
                }
                else {
                    next = this.currentSelection.getNext('li');
                }
            }
            else if(ev.key == 'up') {
                if(this.currentSelection == null || this.currentSelection.getPrevious() == null) {
                    next = this.ulTag.getLast('li');
                }
                else {
                    next = this.currentSelection.getPrevious('li');
                }
           }
           this.setSelection(next);
        }
    },
    keyUpEvent: function(ev) {

        if(ev.key == 'esc') {
            this.gcList();
        }
        else if(ev.key == 'up' || ev.key == 'down') {
            ev.stop();
            if(!this.suggestionsShown) {
                this.handleInput();
            }
        }
        else if(ev.key == 'enter') {
            ev.stop();
        }
        else {
            this.handleInput();
        }
    },
    changeInput: function(ev) {

        this.inputTag.setStyle('display','none');
        this.inputTag.getNext('em').setStyle('display','');

        var inp = ev.target.getPrevious('input');
        var em = ev.target.getPrevious('em');
        if(inp.getStyle('display') == 'none') {
            em.setStyle('display','none');
            inp.setStyle('display','');
            this.inputTag = inp;
        }
        else {
            inp.setStyle('display','none');
            em.setStyle('display','');
        }
        this.cachedData.empty();
    },
    build: function() {
        this.ulTag = document.id('suggest');
        if(!this.ulTag) {
            this.ulTag = new Element('ul#suggest.suggest[style=opacity:0.80;]').inject(document.body);
        }
        this.gcList();
    },
    handleInput: function() {

        this.enteredText = this.inputTag.get('value');
        if(this.enteredText.length >= this.options.minLength){

            var cords = this.inputTag.getCoordinates();
            this.ulTag.setStyles({'top': cords.top + cords.height, 'left': cords.right - cords.width}); //'width': cords.width

            this.makeRemoteRequest();
        }
    },
    makeRemoteRequest: function() {

        if(this.cachedData.has(this.enteredText)) {
            this.handleIncomingData(this.cachedData.get(this.enteredText));
        }
        else {
            new Request({
                'method': 'get',
                'url': this.options.url,
                'onRequest': function() {
                    this.inputTag.getNext('a').addClass('load');
                }.bind(this),
                'onComplete': function(resp) {
                    this.inputTag.getNext('a').removeClass('load');
                    this.handleIncomingData(resp);
                }.bind(this)
            }).send('table=' + this.options.table + '&q=' + this.enteredText + '&c=' + this.inputTag.retrieve('col') + '&nc=' + Date.now());
        }
    },
    handleIncomingData: function(resp) {
        var data = eval('(' + resp + ')');

        if(!this.cachedData.has(data.query)) {
            this.cachedData.set(data.query, resp);
        }
        this.suggestionData = data.suggestions;
        if(this.suggestionData.length > 0) {
            this.populate();
        }
        else {
            this.gcList();
        }
    },
    populate: function() {
        this.gcList();
        this.suggestionData.each(function(item) {
            for(var key in item){
                this.addSuggestion(key, item[key]);
            }
        }.bind(this));

        this.suggestionsShown = true;
        if(this.ulTag.getElements('li').length > 0) {
            this.ulTag.fade('in');
        }
    },
    addSuggestion: function(key, str) {
        this.ulTag.adopt(
            new Element('li[html=' + str + ']', {
                'events':{
                    'mouseenter': function(ev) {
                        this.setSelection(ev.target);
                    }.bind(this),
                    'mouseleave': function() {
                        this.removeClass('hover');
                    },
                    'click': this.onChoice.bind(this)
              }
            }).store('key', key)
        );
    },
    markup: function(str) {
        var et_regex = new RegExp('(' + this.enteredText + ')', 'i');
        return str.replace(et_regex, '<tt>$1</tt>');
    },
    setSelection: function(el) {
        var hovers = this.ulTag.getElements('li.hover');
        if(hovers) {
            hovers.removeClass('hover');
        }

        this.currentSelection = el;
        if(el) {
            el.addClass('hover');
        }
    },
    onChoice: function(liTag) {
        if(!liTag) return;
        if(typeOf(liTag) == 'event') {
            liTag = liTag.target;
        }

        var key = liTag.retrieve('key');
        this.inputTag.set('value', this.currentSelection.get('text'));

        this.gcList();

        this.fireEvent('choice',[key]);
    },
    gcList: function() {
        this.currentSelection = null;
        this.suggestionsShown = false;
        this.ulTag.empty();
        this.ulTag.fade('out');
    }
});

